﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Subgurim.Controles;
using ControlLogNamespace;
using ControlHorsetrackNamespace;


namespace ControlGeograficoNamespace
{

    /// <summary>
    /// Summary description for Segmento
    /// </summary>
    public class Segmento
    {
        private GLatLng objCoordenada1;
        private GLatLng objCoordenada2;
        private double dbParameterA;
        private double dbParameterB;
        private bool boolParameterXCnst;
        private bool boolParameterYCnst;
        private double dbParameterX;
        private double dbParameterY;

        public Segmento(GLatLng objCoordenada1Param, GLatLng objCoordenada2Param)
        {
            try
            {
                objCoordenada1 = objCoordenada1Param;
                objCoordenada2 = objCoordenada2Param;
                dbParameterA = 0;
                dbParameterB = 0;
                boolParameterXCnst = false;
                boolParameterYCnst = false;
                procesarEcuacionLineal();
            }
            catch (Exception ee)
            {
                ControlLog.writeLog("[Segmento:ctor] Excepcion creando segmento :"+ee.Message);
                throw ee;
            }
 
        }

        private void procesarEcuacionLineal()
        {
            try
            {
                try
                {
                    dbParameterA = procesarParametroA();
                }
                catch (DivideByZeroException divExA)
                {
                    ControlLog.writeLog("[Segmento:procesarEcuacionLineal] La ecuacion es Y=" + dbParameterY.ToString() + " con X valido en el rango(" + objCoordenada1.lng.ToString() + ":" + objCoordenada2.lng.ToString() + ")");
                    return;
                }
                try
                {
                    dbParameterB = procesarParametroB();
                }
                catch (DivideByZeroException divExB)
                {
                    ControlLog.writeLog("[Segmento:procesarEcuacionLineal] La ecuacion es X=" + dbParameterX.ToString() + " con Y valido en el rango(" + objCoordenada1.lat.ToString() + ":" + objCoordenada2.lat.ToString() + ")");
                    return;
                }

                ControlLog.writeLog("[Segmento:procesarEcuacionLineal] La ecuacion es Y=" + getA() + "X + (" + getB() + ") con Y valido en el rango(" + objCoordenada1.lat.ToString() + ":" + objCoordenada2.lat.ToString() + ") y X valido en el rango(" + objCoordenada1.lng.ToString() + ":" + objCoordenada2.lng.ToString() + ")");
            }
            catch(Exception ex)
            {
                ControlLog.writeLog("[Segmento:procesarEcuacionLineal] Excepcion creando segmento :" + ex.Message);
                throw ex;
            }

            return;
        }

        private double procesarParametroB()
        {           
            //Las latitudes son Y
            //Las longitudes son X
            try
            {
                double dbNumerador = objCoordenada2.lat - (objCoordenada1.lat * objCoordenada2.lng / objCoordenada1.lng);
                double dbDenominador = 1 - (objCoordenada2.lng / objCoordenada1.lng);

                return dbNumerador / dbDenominador;
            }
            catch (DivideByZeroException divZeroEx)
            {
                boolParameterXCnst = true;
                boolParameterYCnst = false;
                dbParameterX = objCoordenada2.lng;
                throw divZeroEx;
            }
            catch (Exception ex)
            {
                ControlLog.writeLog("[Segmento:procesarParametroB] Excepcion calculando parametro B :" + ex.Message);
                throw ex;
            }
        }
        private double procesarParametroA()
        {
            //Las latitudes son Y
            //Las longitudes son X
            try
            {
                double dbNumerador = (objCoordenada2.lat - objCoordenada1.lat);
                double dbDenominador = (objCoordenada2.lng - objCoordenada1.lng);
                return dbNumerador / dbDenominador;
            }
            catch(DivideByZeroException divZeroEx)
            {
                boolParameterYCnst = true;
                boolParameterXCnst = false;
                dbParameterY = objCoordenada2.lat;
                throw divZeroEx;
            }
            catch(Exception ex)
            {
                ControlLog.writeLog("[Segmento:procesarParametroA] Excepcion calculando parametro A :" + ex.Message);
                throw ex;
            }
        }


        /// <summary>
        /// Evalua si una determinada longitud (perteneciente a una coordenada de interseccion de una traza de caballo) esta entre las longitudes de puntos de otro segmento
        /// </summary>
        /// <param name="dbLongitudParam">Longitud de la coordenada de la traza</param>
        /// <returns>Devuelve true si la longitud de la traza esta incluida entre las longitudes del otro segmento. Caso contrario false </returns>
        public bool estaLongitudEnRango(double dbLongitudParam)
        {
            if (objCoordenada1.lng <= dbLongitudParam && dbLongitudParam <= objCoordenada2.lng)
            {
                ControlLog.writeLog("[Segmento:estaLongitudEnRango] " + objCoordenada1.lng.ToString() + " <= " + dbLongitudParam.ToString() + " <=" + objCoordenada2.lng.ToString() + " - EN RANGO !");
                return true;
            }
            else if (objCoordenada1.lng >= dbLongitudParam && dbLongitudParam >= objCoordenada2.lng)
            {
                ControlLog.writeLog("[Segmento:estaLongitudEnRango] " + objCoordenada1.lng.ToString() + " >= " + dbLongitudParam.ToString() + " >=" + objCoordenada2.lng.ToString() + " - EN RANGO !");
                return true;
            }
            else
            {
                return false;
            }
        }

        public double getA()
        {
            return dbParameterA;
        }
        public double getB()
        {
            return dbParameterB;
        }

        public double distance(GLatLng objOrig, GLatLng objDest)
        {
            return Math.Sqrt(Math.Pow(objOrig.lat - objDest.lat, 2) +
                             Math.Pow(objOrig.lng - objDest.lng, 2));
        }

        public override string ToString()
        {
            return "(" + objCoordenada1.lat.ToString() + "," + objCoordenada1.lng.ToString() + ")(" + objCoordenada2.lat.ToString() + "," + objCoordenada2.lng.ToString() + ")";
        }
    }


    public class ControlGeografico
    {
        public static bool segmentosIntersectan(Segmento objSegmentoCaballoParam, Segmento objSegmentoPoligonoParam)
        {
            try
            {
                if (objSegmentoCaballoParam.estaLongitudEnRango(calcularInterseccion(objSegmentoCaballoParam, objSegmentoPoligonoParam)))
                {                         
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch(Exception ex)
            {
                ControlLog.writeLog("[ControlGeografico:segmentosIntersectan] Excepcion intersectando segmentos :" + ex.Message);            
                throw ex;
            }
        }

        private static double calcularInterseccion(Segmento objSegmentoCaballoParam, Segmento objSegmentoPoligonoParam)
        {
            Double dbLatitud=0;

            dbLatitud = (objSegmentoPoligonoParam.getB() - objSegmentoCaballoParam.getB() ) / (objSegmentoCaballoParam.getA() - objSegmentoPoligonoParam.getA() );

            return dbLatitud;
        }

        public static bool estaCaballoDentroDeGeofence(Caballo objCaballoAAnalizar, GeoFence objGeoFenceAAnalizar)
        {
            try
            {
                Segmento objSegmentoDeReferencia = new Segmento(objCaballoAAnalizar.objPosicion.getLatLng(), objGeoFenceAAnalizar.objCoordenadaDeReferenciaInterna);
                Trazabilidad objTrazaGeoFence = new Trazabilidad();

                ControlLog.writeLog("[ControlGeografico:estaCaballoDentroDeGeofence] Segmento de referencia ("+objCaballoAAnalizar.objPosicion.getLatLng().lat+","+objCaballoAAnalizar.objPosicion.getLatLng().lng+")("+ objGeoFenceAAnalizar.objCoordenadaDeReferenciaInterna.lat+","+ objGeoFenceAAnalizar.objCoordenadaDeReferenciaInterna.lng+")");
                foreach (GLatLng objCoordenada in objGeoFenceAAnalizar.objPolygon.points)
                {
                    objTrazaGeoFence.agregarCoordenadas(objCoordenada);
                }

                objTrazaGeoFence.convertirASegmentos();
                ControlLog.writeLog("[ControlGeografico:estaCaballoDentroDeGeofence] Traza de Geofence en segmentos.... OK");
                foreach (Segmento objSegmentoTrazaGeoFence in objTrazaGeoFence.obtenerTrazadoEnSegmentos())
                {
                    if (segmentosIntersectan(objSegmentoDeReferencia, objSegmentoTrazaGeoFence))
                    {
                        ControlLog.writeLog("[ControlGeografico:estaCaballoDentroDeGeofence] Segmentos interesectados: SRef["+objSegmentoDeReferencia.ToString()+"] SGeoFence["+objSegmentoTrazaGeoFence.ToString()+"]");
                        ControlLog.writeLog("[ControlGeografico:estaCaballoDentroDeGeofence] objCaballo "+objCaballoAAnalizar.strNombre+"("+objCaballoAAnalizar.strIDCaballo+") esta fuera del GeoFence. Retornado FALSE");
                        return false;
                    }
                }
                ControlLog.writeLog("[ControlGeografico:estaCaballoDentroDeGeofence] objCaballo "+objCaballoAAnalizar.strNombre+"("+objCaballoAAnalizar.strIDCaballo+") esta dentro del GeoFence. Retornando TRUE");
              
                return true;
            }
            catch(Exception ex)
            {
                ControlLog.writeLog("[ControlGeografico:estaCaballoDentroDeGeofence] Excepcion calculando algoritmo :" + ex.Message);
                throw ex;
            }
        }

        public static bool pasaCaballoPorCheckPoint(Caballo objCaballoAAnalizar, GeoCheckPoint objCheckPointAAnalizar)
        {
            try
            {
                Trazabilidad objTrazaGeoCheckPoint = new Trazabilidad();

                ControlLog.writeLog("[ControlGeografico:pasaCaballoPorCheckPoint] Calculando traza de GeoCheckpoint....");
                foreach (GLatLng objCoordenada in objCheckPointAAnalizar.obtenerTrazaPorCoordenadas())
                {
                    objTrazaGeoCheckPoint.agregarCoordenadas(objCoordenada);
                }

                objTrazaGeoCheckPoint.convertirASegmentos();

                ControlLog.writeLog("[ControlGeografico:pasaCaballoPorCheckPoint] Calculando algoritmo de interseccion....");
                foreach (Segmento objSegmentoCaballo in objCaballoAAnalizar.objTrazabilidad.obtenerTrazadoEnSegmentos())
                {
                    foreach (Segmento objSegmentoCheckPoint in objTrazaGeoCheckPoint.obtenerTrazadoEnSegmentos())
                    {
                        if (segmentosIntersectan(objSegmentoCaballo, objSegmentoCheckPoint))
                        {
                            ControlLog.writeLog("[ControlGeografico:pasaCaballoPorCheckPoint] Segmentos intersectados: SCaballo["+objSegmentoCaballo.ToString()+"] ["+objSegmentoCheckPoint.ToString()+"]. Retorno TRUE");               
                            return true;
                        }
                    }
                }

                ControlLog.writeLog("[ControlGeografico:pasaCaballoPorCheckPoint] El caballo no cruza el GeoCheckPoint. Retorno FALSE");               
                return false;
            }
            catch (Exception ex)
            {
                ControlLog.writeLog("[ControlGeografico:pasaCaballoPorCheckPoint] Excepcion calculando algoritmo :" + ex.Message);
                throw ex;
            }
        }
    }

    
}